import {
  BaseAdapter,
  DHElementData,
  ElemType,
  LineData,
  ModelDataGeom,
  ModelDataMesh,
  PointData,
  RenderAdapterGeom,
} from '@amcax/web-render';
import { VisualDataCloud, VisualDataShape } from '../model/VisualDataShape';

export class RenderAdapterShape extends BaseAdapter<
  VisualDataCloud | VisualDataShape,
  ModelDataMesh | ModelDataGeom
> {
  public convert(
    visualDataArray: (VisualDataCloud | VisualDataShape)[],
  ): (ModelDataMesh | ModelDataGeom)[] {
    const modelData: (ModelDataMesh | ModelDataGeom)[] = [];
    for (const visualData of visualDataArray) {
      console.debug('RenderAdapterMesh visualData', visualData);
      if (visualData.category === 'MESH') {
        const mesh = visualData as VisualDataCloud;
        const position = this.processPosition(mesh);
        if (visualData['type'] === 'POINTCLOUD') {
          const cloud = visualData as VisualDataCloud;
          const cloudItem: ModelDataGeom = {
            id: visualData.id,
            category: 'CLOUD',
            pointData: {
              ids: new Uint32Array(),
              position,
              normal: this.processNormal(cloud),
            },
            lineData: undefined,
            faceData: undefined,
            topology: undefined,
          };
          modelData.push(cloudItem);
        } else {
          // const nodeData = this.processNodes(position); 暂时不需要渲染Node
          const { d2Data } = this.processElements(mesh, position);
          const modelDataItem: ModelDataMesh = {
            id: visualData.id,
            category: visualData.category,
            nodeData: undefined,
            d0Data: undefined,
            d1Data: undefined,
            d2Data,
            d3Data: undefined,
          };
          modelData.push(modelDataItem);
        }
      } else if (visualData.category === 'CURVE') {
        const curve = visualData as VisualDataCloud;
        const { line } = this.processCurve(curve);
        const curveItem: ModelDataGeom = {
          id: visualData.id,
          category: visualData.category,
          pointData: undefined,
          lineData: line,
          faceData: undefined,
          topology: undefined,
        };
        modelData.push(curveItem);
      } else if (visualData.category === 'SHAPE') {
        const shape = visualData as VisualDataShape;
        modelData.push(...this.processGeom(shape));
      }
    }
    console.debug('RenderAdapterMesh converted', modelData);
    return modelData;
  }

  private processPosition(visualData: VisualDataCloud) {
    const points = visualData.cloud?.points ?? visualData.points ?? [];
    return new Float32Array(points);
  }

  private processNormal(visualData: VisualDataCloud) {
    const normal = visualData.cloud?.normals ?? visualData.normals ?? [];
    return new Float32Array(normal);
  }

  private processNodes(position: Float32Array): PointData {
    let ids = new Uint32Array(0);
    // 通过索引生成id
    const length = Math.floor(position.length / 3);
    ids = new Uint32Array(length);
    for (let i = 0; i < length; i++) {
      ids[i] = i;
    }
    return {
      ids,
      position,
    };
  }

  /**
   * 处理单元，包括 0维、1维、2维、3维单元
   * @param visualDataElements
   * @param nodeIdIndexMap
   * @param position
   * @returns
   */
  private processElements(
    visualData: VisualDataCloud,
    position: Float32Array,
  ): {
    d2Data?: DHElementData;
  } {
    // 将facets处理成 2维 单元渲染
    const facets = visualData.cloud?.facets ?? visualData.facets ?? [];
    // 通过索引生成id等
    const length = Math.floor(facets.length / 3);
    const ids = new Uint32Array(length);
    const elementType = new Uint8Array(length);
    const vertexStartIndices = new Uint32Array(length + 1);
    const renderIndices = new Uint32Array(facets);
    const wireOrders = [0, 1, 1, 2, 2, 0];
    const wireLength = wireOrders.length;
    const wires = new Uint32Array(length * wireLength);
    const wireStartIndices = new Uint32Array(length + 1);
    for (let i = 0; i < length; i++) {
      ids[i] = i;
      elementType[i] = ElemType.Tri_3;
      vertexStartIndices[i] = i * 3;
      for (let j = 0; j < wireOrders.length; j++) {
        wires[i * wireLength + j] = facets[i * 3 + wireOrders[j]];
      }
      wireStartIndices[i] = i * wireLength;
    }
    vertexStartIndices[length] = length * 3;
    wireStartIndices[length] = length * wireLength;
    // 2维 单元渲染数据
    const d2Data = {
      ids,
      elementType,
      position,
      vertexStartIndices,
      renderIndices,
      wires,
      wireStartIndices,
    };
    return { d2Data };
  }

  private processCurve(visualData: VisualDataCloud): { line?: LineData } {
    const points = visualData.cloud?.points ?? visualData.points;
    const length = Math.floor(points.length / 3);
    const ids = new Uint32Array([0]);
    const renderType = new Uint8Array([0]);
    const vertexStartIndices = new Uint32Array([0, length * 2 - 2]);
    const position = new Array<number>();
    // 线要一段一段渲染，所以除首尾之外，中间的都重复一次
    const pointLength = points.length / 3; // 三个一组
    if (pointLength === 0) {
      return {};
    }
    for (let j = 0; j < pointLength - 1; j++) {
      position.push(points[j * 3], points[j * 3 + 1], points[j * 3 + 2]);
      position.push(points[j * 3 + 3], points[j * 3 + 4], points[j * 3 + 5]);
    }
    const line = {
      ids,
      position: new Float32Array(position),
      vertexStartIndices,
      renderType,
    };
    return { line };
  }

  private processGeom(visualData: VisualDataShape) {
    const geom = visualData.geom;
    if (geom) {
      visualData.vertices = geom.vertices;
      visualData.edges = geom.edges;
      visualData.faces = geom.faces;
    }
    // 直接复用已有的RenderAdapterGeom，就不必重复实现了
    return new RenderAdapterGeom(null, null).convert([visualData]);
  }
}
